#include "telephoneBook.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


// 创建通讯录
TelBook *InitTelBook(int capacity, void (*FreePtr)(ElementType))
{
    // 申请通讯录结构体内存
    TelBook *book = (TelBook *)malloc(sizeof(TelBook));
    if(book == NULL)
    {
        printf("申请TelBook失败!\n");
        return NULL;
    }

    // 分配联系人数组的内存
    book->contacts = (ElementType*)malloc(sizeof(ElementType) * capacity);
    if(book->contacts == NULL)
    {
        printf("申请联系人数组失败！\n");
        free(book);
        return NULL;
    }

    // 初始化容量和当前大小
    book->capacity = capacity;
    book->size = 0;
    book->FreePtr = FreePtr;

    return book;
}

// 释放通讯录
void FreeTelBook(TelBook *book)
{
    if(book)
    {   
        // 确保联系人数组不为空
        if(book->contacts)
        {
            // 释放每一个联系人
            for(int i = 0; i < book->size; i++)
            {
                ContInfo *cont = (ContInfo *)book->contacts[i];
                if(cont)
                {
                    // 调用释放函数
                    if(book->FreePtr != NULL)
                    {
                        book->FreePtr(book->contacts[i]);
                    }

                    // free(cont->name);
                    // free(cont->phone);
                    // free(cont);
                }
            }
            // 释放联系人数组
            free(book->contacts); 
        }
        // 释放通讯录结构体
        free(book);
    }
}

// 快排函数
void FastSort(ElementType *contacts, int start, int end, bool (*SortPtr)(ElementType, ElementType))
{
    // 终止条件
    if(start >= end)
        return;

    int left = start;
    int right = end;
    ElementType temp = contacts[left];

    while(left < right)
    {
        // 先从右边动 找比基准值小的数
        while(SortPtr(contacts[right], temp) == true && left < right)
            right--;
        // 把右边的值赋给左边的空位 
        if(left < right)
            contacts[left] = contacts[right];
        // 左边动 找比基准值大的数
        while(SortPtr(temp, contacts[left]) == true && left < right)
            left++;
        // 把左边的值赋给右边的空位
        if(left < right)
            contacts[right--] = contacts[left];
    }
    // 基准值给到这个位置
    contacts[left] = temp;

    // 递归排序
    FastSort(contacts, start, left - 1, SortPtr);
    FastSort(contacts, right + 1, end, SortPtr);
}

// 快速排序
void TelBookFastSort(TelBook *book, bool (*SortPtr)(ElementType, ElementType))
{
    FastSort(book->contacts, 0, book->size - 1, SortPtr);
}

// 按名字快排
bool SortByName(ElementType a, ElementType b)
{
    ContInfo *contA = (ContInfo *)a;
    ContInfo *contB = (ContInfo *)b;

    return strcmp(contA->name, contB->name) > 0;
}

//插入联系人
bool InsertCont(TelBook *book, const char *name, const char *phone)
{
    // 检查容量是否够
    if(book->size >= book->capacity)
    {
        // 扩容联系人数组
        ElementType *newCapacity = (ElementType *)realloc(book->contacts, sizeof(ElementType) * book->capacity * 2);
        // 检查是否扩容成功
        if(newCapacity == NULL)
        {
            printf("扩容失败！\n");
            return false;
        }
        book->contacts = newCapacity;
        book->capacity *= 2;
    }

    // 为新联系人分配空间
    ContInfo *newCont = (ContInfo *)malloc(sizeof(ContInfo));
    // 检查是否新建成功
    if(newCont == NULL)
    {
        printf("新建联系人失败！\n");
        return false;
    }

    // 复制原联系人字符串并为新联系人字符串分配内存
    newCont->name =  strdup(name);
    newCont->phone = strdup(phone);
    // 检查是否复制和分配成功
    if(newCont->name == NULL || newCont->phone == NULL)
    {
        // 分配失败，释放内存
        book->FreePtr(book->contacts);

        // free(newCont->name);
        // free(newCont->phone);
        // free(newCont);
        return false;
    }

    // 添加联系人到通讯录
    book->contacts[book->size] = newCont;
    book->size++;

    // 快排
    TelBookFastSort(book, SortByName);
    return true;
}

// 按名字删除联系人
bool DeleteByName(TelBook *book, const char *name)
{
    for(int i = 0; i < book->size; i++)
    {
        ContInfo *cont = (ContInfo *)book->contacts[i];
        if(strcmp(cont->name, name) == 0)
        {
            // 调用释放函数
            // 判空
            if(book->FreePtr != NULL)
            {
                book->FreePtr(cont);
            }
            // book->FreePtr(book->contacts);

            // free(cont->name);
            // free(cont->phone);
            // free(cont);

            // 移动联系人数组中的元素
            for(int j = i; j < book->size; j++)
            {
                book->contacts[j] = book->contacts[j + 1];
            }
            book->size--;
            return true;
        }
    }
    return false; 
}

// 按电话删除联系人
bool DeleteByPhone(TelBook *book, const char *phone)
{
    for(int i = 0; i < book->size; i++)
    {
        ContInfo *cont = (ContInfo *)book->contacts[i];
        if(strcmp(cont->phone, phone) == 0)
        {
            // 调用释放函数
            if(book->FreePtr != NULL)
            {
                book->FreePtr(cont);
            }
            // book->FreePtr(book->contacts);

            // free(cont->name);
            // free(cont->phone);
            // free(cont);

            // 移动联系人数组中的元素
            for(int j = i; j < book->size; j++)
            {
                book->contacts[j] = book->contacts[j + 1];
            }
            book->size--;
            return true;
        }
    }
    return false;
}

// 修改联系人信息
bool ModifyContact(TelBook *book, const char *oldName, const char *newName, const char *newPhone)
{
    for(int i = 0; i < book->size; i++)
    {
        ContInfo *cont = (ContInfo *)book->contacts[i];
        if(strcmp(cont->name, oldName) == 0)
        {
            // 释放旧的名字和电话
            free(cont->name);
            free(cont->phone);

            // 复制和分配新的名字和电话
            cont->name = strdup(newName);
            cont->phone = strdup(newPhone);

            // 判空
            if(cont->name == NULL || cont->phone == NULL)
            {
                return false;
            }
            return true;
        }
    }
    return false;
}

// 二分查询
ElementType BinarySearch(TelBook *book, ElementType element, int (*BSearch)(ElementType, ElementType))
{
    int left = 0;
    int right = book->size - 1;
    while(left <= right)
    {
        // int mid = left + (right - left) / 2;
        int mid = (left & right) + ((left ^ right) >> 1);   // 要把后面异或求平均值的部分整个括起来！
        // 比中间值小
        if(BSearch(book->contacts[mid], element) > 0)
            // 左半边找
            right = mid - 1;
        else if(BSearch(book->contacts[mid], element) < 0)
            // 右半边找
            left = mid + 1;
        else
            // 找着了
            return book->contacts[mid];
    }
    // 没找到
    return NULL;
}

// 按名字模糊查询
void SearchByName(TelBook *book, const char *subString)
{
    for(int i = 0; i < book->size; i++)
    {
        ContInfo *cont = (ContInfo *)book->contacts[i];

        // 检查名字中是否包含子串
        if(strstr(cont->name, subString))
        {
            printf("Name: %s, Phone: %s\n", cont->name, cont->phone);
        }
    }
}

// 按电话模糊查询
void SearchByPhone(TelBook *book, const char *subString)
{
    for(int i = 0; i < book->size; i++)
    {
        ContInfo *cont = (ContInfo *)book->contacts[i];

        // 检查电话中是否包含子串
        if(strstr(cont->phone, subString))
        {
            printf("Name: %s, Phone: %s\n", cont->name, cont->phone);
        }
    }
}

// 显示所有联系人信息
void Show(TelBook *book)
{
    // 判空
    if(book == NULL || book->contacts == NULL)
    {
        printf("通讯录为空！\n");
    }

    // 遍历并打印所有联系人信息
    for(int i = 0; i < book->size; i++)
    {
        ContInfo *cont = (ContInfo *)book->contacts[i];
        if(cont)
        {
            printf("Name: %s, Phone: %s\n", cont->name, cont->phone);
        }
    }
}

void SaveBook(TelBook *book, char *(*GetInfo)(void *))
{
    FILE *f = fopen("./book.txt", "w");
    if(f == NULL)
    {
        printf("文件打开失败!保存文件失败!\n");
        return;
    }

    for(int i = 0; i < book->size; i++)
    {
        char *s = GetInfo(book->contacts[i]);
        fprintf(f, "%s", s);
        free(s);
    }
    fclose(f);
}

char *GetInfo(void *ptr)
{
    ContInfo *p = (ContInfo *)ptr;
    // 格式化输入到字符串中
    char s[256] = {0};
    sprintf(s, "name = %s tel = %s\n", p->name, p->phone);
    return strdup(s);
}

void ReadFromBook(TelBook *book)
{
    FILE *f = fopen("./book.txt", "r");
    if(f == NULL)
    {
        printf("文件打开失败!保存文件失败!\n");
        return;
    }

    while(1)
    {
        char name[20];
        char phone[20];
        if(fscanf(f, "name = %s tel = %s\n", name, phone) < 0)
        {
            break;
        }

        InsertCont(book, name, phone);
        printf("%s %s\n", name, phone);
    }
    fclose(f);
}

void *Create(char *name, char *phone)
{
    return 
}